﻿
using Microsoft.Extensions.DependencyInjection;
using Stee.CAP8.MessageBus.Sagas.Core.Pipeline.Reiceve;
using Stee.CAP8.MessageBus.Sagas.Core.Processes;
using Stee.CAP8.MessageBus.Sagas.Core.Sagas;
using Stee.CAP8.MessageBus.Sagas.Core.Steps;
using Stee.CAP8.MessageBus.Sagas.Core.SubscribeStores;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Stee.CAP8.MessageBus.Sagas.Core.Extensions
{
    public static class EventBusExtension
    {

        public static IServiceCollection UseKafkaSubsrcibeStore(this IServiceCollection services)
        {
            services.AddSingleton(typeof(ISubscribeStore), typeof(KafkaSubscribeStore));
            services.AddSingleton(typeof(IIncomingStep), typeof(ActivateHandlersStep));
            services.AddSingleton(typeof(ISagaStorage), typeof(InMemorySagaStorage));
            services.AddSingleton(typeof(IHandlerProvider), typeof(HandlerProvider));

            return services;
        }

        public static void AddSubscrbe<TMssage>(this IServiceCollection services)
        {
            var provider = services.BuildServiceProvider();
            var handlerType = typeof(IHandleMessages<TMssage>);
            var handlers = provider.GetServices(typeof(IHandleMessages<TMssage>)).Cast<IHandleMessages<TMssage>>();

            ISubscribeStore store = provider.GetService<ISubscribeStore>();

            foreach (var handler in handlers)
            {

                Func<TMssage, Task> callback = new Func<TMssage, Task>(handler.Handle);
                store.AddHandler<TMssage>(handler, callback);
            }

        }


        public static void AddSaga<TSaga>(this IServiceCollection services) where TSaga : Saga
        {
            var provider = services.BuildServiceProvider();
            var sagaType = typeof(TSaga);
            var baseType = sagaType.BaseType;
            var baseTypes = sagaType.GetBaseTypes()
                .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(Saga<>));
            var interfaces = sagaType.GetInterfaces()
                .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandleMessages<>));
            var interface0 = interfaces.First();

            var types = AppDomain.CurrentDomain.GetAssemblies()
                        .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(interface0)))
                        .ToArray();


            var steps = provider.GetService<IIncomingStep>();


            Console.WriteLine();



        }


        public static IServiceCollection AddEventBus(this IServiceCollection services)
        {
            services.AddSingleton(typeof(IBus), typeof(EventBus));


            return services;
        }

        public static IServiceCollection UseEventBus(this IServiceCollection services, Action<IBus> busAction)
        {
            var provider = services.BuildServiceProvider();
            if (provider == null) throw new ArgumentNullException(nameof(provider));
            if (busAction == null) throw new ArgumentNullException(nameof(busAction));


            var bus = provider.GetService<IBus>();

            busAction(bus);

            return services;
        }



        public static IServiceCollection AddMessagebusHandler<THandler>(this IServiceCollection services) where THandler : IHandleMessages
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            RegisterType(services, typeof(THandler));
            return services;
        }

        static void RegisterType(IServiceCollection services, Type typeToRegister)
        {
            var implementedHandlerInterfaces = GetImplementedHandlerInterfaces(typeToRegister).ToArray();

            foreach (var handlerInterface in implementedHandlerInterfaces)
            {
                services.AddTransient(handlerInterface, typeToRegister);
            }
        }


        static IEnumerable<Type> GetImplementedHandlerInterfaces(Type type) =>
            type.GetInterfaces()
                .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandleMessages<>));

    }
}
